package service.impl;

import exception.BusinessException;
import model.entity.Item;
import model.entity.Order;
import model.enums.ExceptionCode;
import model.enums.ItemType;
import model.enums.OrderStatus;
import service.OrderRepository;

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author WeiJin
 * @Version 1.0
 * @Date 2025/3/25 10:01
 */
public class SimpleOrderService extends BaseOrderService {

    public SimpleOrderService(OrderRepository repository) {
        super(repository);
    }

    @Override
    public Order createOrder(List<Item> items, boolean isVIP, LocalDateTime currentTime) {
        // 1. 基础校验
        validateItems(items);

        Order order = new Order(UUID.randomUUID().toString(),
                OrderStatus.CREATED,
                currentTime);
        // 2. 处理时间敏感商品
        List<Item> filteredItems = filterTimeSensitiveItems(items, currentTime.toLocalTime());

        // 3. 计算价格（示例代码片段）
        double totalPrice = calculateTotalPrice(order,filteredItems, isVIP, currentTime);

        // 4. 构建订单
        order.setItems(filteredItems);
        order.setTotalPrice(totalPrice);

        // 判断冰咖啡是否下架
        boolean hasIceCafe = items.stream().anyMatch(item -> "冰咖啡".equals(item.getName())
                && currentTime.toLocalTime().isAfter(LocalTime.of(15, 0)));
        if (hasIceCafe) {
            order.appendRemark("冰咖啡已下架");
        }

        repository.save(order);
        // 模拟一分钟未支付取消订单
        scheduleCancelOrder(order);
        return order;
    }


    @Override
    public void cancelOrder(String orderId, LocalDateTime currentTime) {
        // 获取订单
        Order order = this.repository.findById(orderId);
        if (Objects.isNull(order)) {
            throw new BusinessException(ExceptionCode.ORDER_IS_NULL);
        }
        // 判断是否已支付
        if (OrderStatus.PAID.equals(order.getStatus())) {
            throw new BusinessException(ExceptionCode.ORDER_PAID);
        }
        // 取消订单
        this.repository.updateStatus(orderId, OrderStatus.CANCELLED);
    }



    /**
     * 计算价格
     *
     * @param filteredItems 需处理事时间的敏感商品
     * @param isVIP         是否VIP用户
     * @param currentTime   下单时间
     * @return 返回价格
     */
    public double calculateTotalPrice(Order order, List<Item> filteredItems, boolean isVIP, LocalDateTime currentTime) {
        // 计算套餐价格（汉堡＋薯条）
        boolean hasHamburger = filteredItems.stream().anyMatch(item -> "汉堡".equals(item.getName()));
        boolean hasChip = filteredItems.stream().anyMatch(item -> "薯条".equals(item.getName()));
        double totalPrice = 0;
        if (hasHamburger && hasChip) {
            // 获取汉堡
            List<Item> hamburgerItems = filteredItems.stream()
                    .filter(item -> "汉堡".equals(item.getName()))
                    .collect(Collectors.toList());
            // 获取薯条
            List<Item> chipItems = filteredItems.stream()
                    .filter(item -> "薯条".equals(item.getName()))
                    .collect(Collectors.toList());
            // 计算套餐价格
            int extraNum = hamburgerItems.size() - chipItems.size();
            if (extraNum >= 0) {
                // 汉堡数量大于薯条数量 以薯条数量为套餐基数，多余汉堡另外计费
                totalPrice += 25 * chipItems.size();
                // 计算汉堡数量大于薯条数量的汉堡价钱
                totalPrice += hamburgerItems.get(0).getPrice() * extraNum;
            } else {
                // 薯条数量大于汉堡数量，以汉堡数量为套餐基数，其余薯条另外计费
                totalPrice += 25 * hamburgerItems.size();
                totalPrice += chipItems.get(0).getPrice() * Math.abs(extraNum);
            }
            // 移除汉堡和薯条
            filteredItems = filteredItems.stream()
                    // 过滤掉汉堡或薯条，收起其他数据，避免重复计费
                    .filter(item -> !"汉堡".equals(item.getName()) && !"薯条".equals(item.getName()))
                    .collect(Collectors.toList());
        }
        // 计算第二杯饮品半价
        // 获取所有饮品
        List<Item> drinkItems = filteredItems.stream()
                .filter(item -> ItemType.DRINK.equals(item.getType()))
                .collect(Collectors.toList());
        // 饮品为空或只有一个饮品无需计算第二杯相同饮品半价
        // 用于存放每种饮品数量，key为商品，value为数量
        Map<Item, Integer> sameDrunkMap = new HashMap<>();
        if (!drinkItems.isEmpty() && drinkItems.size() > 1) {
            // 存放每种饮品和数量
            drinkItems.forEach(item -> {
                // 先获取map中的数量
                Integer number = sameDrunkMap.get(item);
                // 非空处理,map中没有该商品，给值为1，放进map
                number = number == null ? 1 : number;
                if (sameDrunkMap.containsKey(item)) {
                    number++;
                }
                sameDrunkMap.put(item, number);
            });
            // 计算饮品的价格
            for (Map.Entry<Item, Integer> entry : sameDrunkMap.entrySet()) {
                Item item = entry.getKey();
                Integer number = entry.getValue();
                // 第二杯半价数量
                int halfNumber = number / 2;
                // 全价数量
                int fullNumber = number % 2;
                totalPrice += item.getPrice() * (halfNumber * 1.5) + item.getPrice() * fullNumber;
            }
            // 所有饮品计算完价格，把饮品移除
            filteredItems = filteredItems.stream()
                    .filter(item -> !ItemType.DRINK.equals(item.getType()))
                    .collect(Collectors.toList());
        }
        // 饮品只有一杯或没有饮品，不会移除饮品，正常计算价格即可
        // 获取计算其他商品价格
        totalPrice += filteredItems.stream().mapToDouble(Item::getPrice).sum();

        // 周末每满100减10
        if (isWeekend(currentTime)) {
            int fullHundredCount = (int) (totalPrice / 100);
            int discountPrice = fullHundredCount * 10;
            totalPrice = totalPrice - discountPrice;
            if (discountPrice > 0){
                order.appendRemark("周末每满100减10活动，共计满减" + discountPrice + "元");
            }
        }

        // 计算VIP用户9折优惠
        if (isVIP) {
            totalPrice = totalPrice * 0.9;
            order.appendRemark("您是VIP用户，享受九折优惠");
        }
        return totalPrice;
    }

    /**
     * 判断某个时间是否为周末
     *
     * @param dateTime 时间
     * @return true or false
     */
    private boolean isWeekend(LocalDateTime dateTime) {
        if (Objects.isNull(dateTime)) {
            return false;
        }
        DayOfWeek dayOfWeek = dateTime.getDayOfWeek();
        return dayOfWeek.equals(DayOfWeek.SUNDAY) || dayOfWeek.equals(DayOfWeek.SATURDAY);
    }

    /**
     * 基础校验
     *
     * @param items 商品列表
     */
    private void validateItems(List<Item> items) {
        // 校验空订单
        if (Objects.isNull(items) || items.isEmpty()) {
            throw new BusinessException(ExceptionCode.EMPTY_ORDER);
        }
        // 校验商品数量，超过五个抛出异常
        if (items.size() > 5) {
            throw new BusinessException(ExceptionCode.TOO_MANY_ITEMS);
        }
        // 校验主食 使用stream流过滤商品类型为主食的商品，并统计个数,没有主食抛出异常
        long count = items.stream().filter(item -> item.getType().equals(ItemType.MAIN)).count();
        if (count == 0) {
            throw new BusinessException(ExceptionCode.NO_MAIN_DISH);
        }
        // 甜品不能单独购买（必须搭配主食）无需校验，没有主食走不到这里来

    }

    /**
     * 定时任务超时未支付取消订单
     *
     * @param order 订单
     */
    private void scheduleCancelOrder(Order order) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                Order order1 = repository.findById(order.getOrderId());
                if (order1.getStatus().equals(OrderStatus.CREATED)) {
                    repository.updateStatus(order.getOrderId(), OrderStatus.CANCELLED);
                    System.out.println("订单超时，已自动取消");
                }
            }
        }, 1000 * 60);
    }


    // 筛选时间敏感项目
    private List<Item> filterTimeSensitiveItems(List<Item> items, LocalTime currentTime) {
        return items.stream()
                .filter(item -> {
                    if ("冰咖啡".equals(item.getName())) {
                        return currentTime.isBefore(LocalTime.of(15, 0));
                    }
                    return true;
                })
                .collect(Collectors.toList());
    }
}